package org.monkey.common.cbs.entity.form;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.MappedSuperclass;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.monkey.common.cbs.entity.mo.FieldFilter;
import org.monkey.common.cbs.entity.mo.FieldOrder;
import org.monkey.common.constant.entity.ErrorResultEnum;
import org.monkey.common.constant.exception.BaseException;
import org.monkey.common.constant.util.MonkeyStrUtil;

@Slf4j
@Data
@MappedSuperclass
@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseQueryForm<T> {
  @JsonIgnore
  @JSONField(serialize = false)
  @com.alibaba.fastjson2.annotation.JSONField(serialize = false)
   static final Map<String, Boolean> MAP = new HashMap<>();

  @JsonIgnore
  @JSONField(serialize = false)
  @com.alibaba.fastjson2.annotation.JSONField(serialize = false)
   static String DELETED_FIELD = "deleted";

  @JsonIgnore
  @JSONField(serialize = false)
  @com.alibaba.fastjson2.annotation.JSONField(serialize = false)
   static String CTD_TIME = "ctd_time";

  @JsonIgnore
  @JSONField(serialize = false)
  @com.alibaba.fastjson2.annotation.JSONField(serialize = false)
   Class<T> entityClass;

  public boolean hasField(String filedName) {
    if (entityClass != null) {
      String key = entityClass.toGenericString() + "." + filedName;
      Boolean ff = MAP.get(key);
      if (ff == null) {
        Field[] fields = ReflectUtil.getFields(entityClass);
        for (Field field : fields) {
          if (field.getName().equals(filedName)) {
            MAP.put(key, true);
            return true;
          }
        }
        MAP.put(key, false);
        return false;
      } else {
        return ff;
      }
    } else {
      return false;
    }
  }
  /**
   * 前端过滤参数转MybatisPlus查询条件 如果filters不包含deleted且要查询的表中有deleted字段则默认会加上deleted=false 筛选条件
   *
   * @param fieldFilters List<FieldFilter> fieldFilters
   * @param rootQueryWrapper QueryWrapper<T>
   * @author liting
   * @date 2020/9/4 11:56
   * @version 1.0
   */
  QueryWrapper<T> filterToWrapper(
      QueryWrapper<T> rootQueryWrapper, List<FieldFilter> fieldFilters) {
    if (fieldFilters == null) {
      fieldFilters = new ArrayList<>();
    }
    boolean flag = fieldFilters.stream().noneMatch(ff -> DELETED_FIELD.equals(ff.getFieldName()));
    if (flag && hasField(DELETED_FIELD)) {
      FieldFilter ft = new FieldFilter();
      ft.setFiledValue(false);
      ft.setFieldName(DELETED_FIELD);
      fieldFilters.add(ft);
    }
    if (fieldFilters.size() > 0) {
      for (FieldFilter fieldFilter : fieldFilters) {
        if (StrUtil.isNotBlank(fieldFilter.getFieldName())) {
          String fieldName = fieldFilter.getFieldName();
          if (isHump()) {
            fieldName = MonkeyStrUtil.humpToUnderline(fieldName);
          }
          if (fieldFilter.getFiledValue() != null
              || fieldFilter.getFilterType().equals(FieldFilter.RG)) {
            if (!fieldFilter.getFilterType().equals(FieldFilter.RG)
                && fieldFilter.getFiledValue() instanceof String
                && StrUtil.isBlank(String.valueOf(fieldFilter.getFiledValue()))) {
              continue;
            }
            switch (fieldFilter.getFilterType()) {
              case FieldFilter.EQ:
                rootQueryWrapper.eq(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.GT:
                rootQueryWrapper.gt(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.GTE:
                rootQueryWrapper.ge(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.LT:
                rootQueryWrapper.lt(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.LTE:
                rootQueryWrapper.le(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.FULL_LIKE:
                rootQueryWrapper.like(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.RIGHT_LIKE:
                rootQueryWrapper.likeRight(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.LEFT_LIKE:
                rootQueryWrapper.likeLeft(fieldName, fieldFilter.getFiledValue());
                break;
              case FieldFilter.RG:
                rootQueryWrapper.between(
                    fieldName,
                    fieldFilter.getRange().getMinValue(),
                    fieldFilter.getRange().getMaxValue());
                break;
              default:
                log.error("未知的过滤类型：{}", fieldFilter.getFilterType());
                throw new BaseException(ErrorResultEnum.PARAM_VALID);
            }
          }
        }
      }
    }
    return rootQueryWrapper;
  }

  /**
   * 前端排序参数转MybatisPlus查询条件 如果orders为空 则默认加上ctdTime倒序排序
   *
   * @param rootQueryWrapper QueryWrapper<T>
   * @param fieldOrders List<FieldOrder> fieldFilters
   * @author liting
   * @date 2020/9/4 11:56
   * @version 1.0
   */
  public QueryWrapper<T> orderToWrapper(
      QueryWrapper<T> rootQueryWrapper, List<FieldOrder> fieldOrders) {
    if (fieldOrders == null) {
      fieldOrders = new ArrayList<>();
    }
    if (fieldOrders.isEmpty()) {
      FieldOrder createdTime = new FieldOrder();
      createdTime.setFieldName(CTD_TIME);
      createdTime.setOrderType("desc");
      fieldOrders.add(createdTime);
    }
    for (FieldOrder fieldOrder : fieldOrders) {
      String fieldName = fieldOrder.getFieldName();
      if (isHump()) {
        fieldName = MonkeyStrUtil.humpToUnderline(fieldOrder.getFieldName());
      }
      if (fieldOrder.getOrderType() != null && FieldOrder.DESC.equals(fieldOrder.getOrderType())) {
        rootQueryWrapper.orderByDesc(fieldName);
      } else {
        rootQueryWrapper.orderByAsc(fieldName);
      }
    }
    return rootQueryWrapper;
  }

  abstract boolean isHump();
}
